package com.spzx.product.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.bean.BeanUtils;
import com.spzx.common.redis.cache.GuiguCache;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.SkuPrice;
import com.spzx.product.api.domain.SkuQuery;
import com.spzx.product.api.domain.vo.SkuStockVo;
import com.spzx.product.api.domain.Product;
import com.spzx.product.api.domain.ProductDetails;
import com.spzx.product.domain.SkuStock;
import com.spzx.product.mapper.ProductDetailsMapper;
import com.spzx.product.mapper.ProductMapper;
import com.spzx.product.mapper.ProductSkuMapper;
import com.spzx.product.mapper.SkuStockMapper;
import com.spzx.product.service.IProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
    @Autowired
    ProductMapper productMapper;
    @Autowired
    ProductSkuMapper productSkuMapper;
    @Autowired
    SkuStockMapper skuStockMapper;
    @Autowired
    ProductDetailsMapper productDetailsMapper;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 分页查询
     *
     * @param product
     * @return
     */
    @Override
    public List<Product> selectList(Product product) {
        List<Product> productList = productMapper.selectAllList(product);
        return productList;
    }

    /**
     * 新增商品
     *
     * @param product
     * @return
     */
    @Transactional
    @Override
    public Integer insertProduct(Product product) {
        //1.先将商品spu的信息保存
        productMapper.insert(product);//主键回填
        Long productId = product.getId();

        List<ProductSku> productSkuList = product.getProductSkuList();
        for (int i = 0; i < productSkuList.size(); i++) {
            //2.保存多个sku
            ProductSku productSku = productSkuList.get(i);
            productSku.setSkuCode(productId + "_" + i);
            productSku.setSkuName(product.getName() + " " + productSku.getSkuSpec());
            productSku.setProductId(productId);
            productSku.setStatus(0);
            productSkuMapper.insert(productSku);//主键回填
            //3.保存商品SKU
            SkuStock skuStock = new SkuStock();
            skuStock.setSkuId(productSku.getId());
            skuStock.setTotalNum(productSku.getStockNum());
            skuStock.setLockNum(0);
            skuStock.setAvailableNum(productSku.getStockNum());
            skuStock.setSaleNum(0);
            skuStock.setStatus(0);
            skuStockMapper.insert(skuStock);
        }
        //4.保存图片详情
        ProductDetails productDetails = new ProductDetails();
        productDetails.setProductId(productId);
        productDetails.setImageUrls(String.join(",", product.getDetailsImageUrlList()));
        productDetailsMapper.insert(productDetails);
        return 1;
    }

    /**
     * 查询商品详情
     *
     * @param id
     * @return
     */
    @Transactional
    @Override
    public Product selectProductById(Long id) {
        //商品信息
        Product product = productMapper.selectById(id);

        if (product == null) {
            throw new ServiceException("数据不存在!");
        }

        //商品sku列表
        List<ProductSku> productSkuList = productSkuMapper
                .selectList(new LambdaQueryWrapper<ProductSku>().eq(ProductSku::getProductId, id));
        product.setProductSkuList(productSkuList);

        //获取每一个skuStock库存值，封装在sku对象中
        List<Long> skuList = productSkuList.stream().map(ProductSku::getId).toList();

        //查询库存
        List<SkuStock> skuStockList = skuStockMapper
                .selectList(new LambdaQueryWrapper<SkuStock>().in(SkuStock::getSkuId, skuList));
        Map<Long, Integer> skuIdToTotalNumMap = skuStockList.stream()
                .collect(Collectors.toMap(SkuStock::getSkuId, SkuStock::getTotalNum));
        for (ProductSku productSku : productSkuList) {
            productSku.setStockNum(skuIdToTotalNumMap.get(productSku.getId()));
        }
        product.setProductSkuList(productSkuList);

        //查询详情图片
        ProductDetails productDetails = productDetailsMapper
                .selectOne(new LambdaQueryWrapper<ProductDetails>().eq(ProductDetails::getProductId, id));
        product.setDetailsImageUrlList(Arrays.asList(productDetails.getImageUrls().split(",")));

        return product;
    }

    /**
     * 修改商品信息
     *
     * @param product
     * @return
     */
    @Transactional
    @Override
    public Integer updateProduct(Product product) {
        //修改商品信息
        productMapper.updateById(product);

        List<ProductSku> productSkuList = product.getProductSkuList();
        for (ProductSku productSku : productSkuList) {
            //修改多个sku
            productSku.setSkuName(product.getName() + " " + productSku.getSkuSpec());
            productSkuMapper.updateById(productSku);
            //修改多个SkuStock
            SkuStock skuStock = skuStockMapper
                    .selectOne(new LambdaQueryWrapper<SkuStock>().eq(SkuStock::getSkuId, productSku.getId()));
            skuStock.setTotalNum(productSku.getStockNum());
            skuStock.setAvailableNum(productSku.getStockNum() - skuStock.getLockNum());
            skuStockMapper.updateById(skuStock);
        }
        //修改详情图片信息
        ProductDetails productDetails = new ProductDetails();
        productDetails.setImageUrls(String.join(",", product.getDetailsImageUrlList()));
        productDetailsMapper.update(productDetails, new LambdaQueryWrapper<ProductDetails>()
                .eq(ProductDetails::getProductId, product.getId()));
        return 1;
    }

    /**
     * 删除商品信息
     *
     * @param ids
     * @return
     */
    @Override
    public Integer deleteProductByIds(List<Long> ids) {
        //删除商品信息
        productMapper.deleteBatchIds(ids);

        //删除商品sku
        List<ProductSku> productSkuList = productSkuMapper
                .selectList(new LambdaQueryWrapper<ProductSku>().in(ProductSku::getProductId, ids));

        List<Long> skuIdList = productSkuList.stream().map(ProductSku::getProductId).toList();
        productSkuMapper.deleteBatchIds(skuIdList);

        //删除库存
        skuStockMapper.delete(new LambdaQueryWrapper<SkuStock>().in(SkuStock::getSkuId, skuIdList));

        //删除商品详情
        productDetailsMapper.delete(new LambdaQueryWrapper<ProductDetails>().in(ProductDetails::getProductId, ids));

        return 1;
    }

    /**
     * 商品审核
     *
     * @param id
     * @param audiStatus
     * @return
     */
    @Transactional
    @Override
    public void updateAudiStatus(Long id, Integer audiStatus) {
        Product product = new Product();
        product.setId(id);
        if (audiStatus == 1) {
            product.setAuditStatus(1);
            product.setAuditMessage("审批通过");
        } else {
            product.setAuditStatus(-1);
            product.setAuditMessage("审批不通过");
        }
        productMapper.updateById(product);
    }

    /**
     * 修改上下架状态
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public void updateStatus(Long id, Integer status) {
        Product product = new Product();
        product.setId(id);
        if (status == 1) {
            product.setStatus(1);

        } else {
            product.setStatus(-1);
        }
        productMapper.updateById(product);
    }


    //===================给前端使用的=========================

    /**
     * 获取销量好的SKU
     *
     * @return
     */
    @Override
    public List<ProductSku> getTopSale() {
        return productSkuMapper.selectTopSale();
    }

    /**
     * 商品列表查询
     *
     * @param skuQuery
     * @return
     */
    @Override
    public List<ProductSku> selectProductSkuList(SkuQuery skuQuery) {
        return productSkuMapper.selectProductSkuList(skuQuery);
    }

    /**
     * 获取商品sku
     *
     * @param skuId
     * @return
     */
    @GuiguCache(prefix = "product:sku:")
    @Override
    public ProductSku getProductSku(Long skuId) {
        return productSkuMapper.selectById(skuId);
    }
    /*//优化版本,单独一个方法加分布式锁
    public ProductSku getProductSku(Long skuId) {
        //优先从缓存中获取数据
        //构建业务数据Key 形式：前缀+业务唯一标识
        String dataKey = "product:skuId:" + skuId;

        //先查询redis缓存，有，直接返回
        ProductSku productSku = null;
        if (redisTemplate.hasKey(dataKey)) {
            productSku = (ProductSku) redisTemplate.opsForValue().get(dataKey);
            log.info("命中缓存，直接返回，线程ID：{}，线程名称：{}",
                    Thread.currentThread().getId(), Thread.currentThread().getName());
            return productSku;
        }

        //2.没有,再查询数据库，放在缓存中，给下次访问使用。利用缓存提高效率。
        String lockKey = "product:skuId:lock:" + skuId;
        String lockVal = UUID.randomUUID().toString().replace("-", "");
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(lockKey, lockVal, 5, TimeUnit.SECONDS);
        if (ifAbsent) {//加分布式锁
            try {
                log.info("获取锁成功：{}，线程名称：{}",
                        Thread.currentThread().getId(), Thread.currentThread().getName());
                productSku = productSkuMapper.selectById(skuId);
                long ttl = productSku == null ? 1 * 60 : 10 * 60;//解决缓存穿透：解决方案一（null值也存储，但是时间较短）
                redisTemplate.opsForValue().set(dataKey, productSku, ttl, TimeUnit.SECONDS);
                return productSku;
            } finally {//执行完业务释放锁，LUA脚本保证原子的唯一性
                String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                        "then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                redisScript.setScriptText(scriptText);
                redisScript.setResultType(Long.class);
                redisTemplate.execute(redisScript, Arrays.asList(lockKey), lockVal);
            }
        } else { //加分布式锁失败，等待自旋
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.error("获取锁失败，自旋：{}，线程名称：{}",
                    Thread.currentThread().getId(), Thread.currentThread().getName());
            return getProductSku(skuId);
        }
    }*/

    /**
     * 获取商品信息
     *
     * @param id
     * @return
     */
    @GuiguCache(prefix = "product:")
    @Override
    public Product getProduct(Long id) {
        return productMapper.selectById(id);
    }

    /**
     * 获取商品sku最新价格信息
     *
     * @param skuId
     * @return
     */
    @GuiguCache(prefix = "skuPrice")
    @Override
    public SkuPrice getSkuPrice(Long skuId) {
        ProductSku productSku = productSkuMapper.selectById(skuId);
        SkuPrice skuPrice = new SkuPrice();
        skuPrice.setSkuId(skuId);
        skuPrice.setSalePrice(productSku.getSalePrice());
        skuPrice.setMarketPrice(productSku.getMarketPrice());
        return skuPrice;
    }


    /**
     * 获取商品详细信息
     *
     * @param id
     * @return
     */
    @GuiguCache(prefix = "productDetails:")
    @Override
    public ProductDetails getProductDetails(Long id) {
        return productDetailsMapper.selectOne(new LambdaQueryWrapper<ProductDetails>().eq(ProductDetails::getProductId, id));
    }


    /**
     * 获取商品sku规则详细信息
     *
     * @param id
     * @return
     */
    @GuiguCache(prefix = "skuSpecValue:")
    @Override
    public Map<String, Long> getSkuSpecValue(Long id) {
        List<ProductSku> productSkuList = productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>()
                .eq(ProductSku::getProductId, id)
                .select(ProductSku::getId, ProductSku::getSkuSpec));
        HashMap<String, Long> skuSpecValueMap = new HashMap<>();
        productSkuList.forEach(item -> {
            skuSpecValueMap.put(item.getSkuSpec(), item.getId());
        });
        return skuSpecValueMap;
    }

    /**
     * 获取商品sku库存信息
     *
     * @param skuId
     * @return
     */
    @GuiguCache(prefix = "skuStockVo:")
    @Override
    public SkuStockVo getSkuStock(Long skuId) {
        SkuStock skuStock = skuStockMapper.selectOne(new LambdaQueryWrapper<SkuStock>().eq(SkuStock::getSkuId, skuId));
        SkuStockVo skuStockVo = new SkuStockVo();
        BeanUtils.copyBeanProp(skuStock, skuStockVo);
        return skuStockVo;
    }

}
